package com.link.base.base.product.service;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.link.base.base.contract.dao.mybatis.mapper.PriContItemTempMapper;
import com.link.base.base.contract.model.PriContItemTempData;
import com.link.base.user.model.CoreUser;
import com.link.core.util.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PriContItemTempListener extends AnalysisEventListener<PriContItemTempData> {

    private static final Logger logger = LogManager.getLogger(PriContItemTempListener.class);

    private PriContItemTempMapper priContItemTempMapper;

    private CoreUser user;

    List<PriContItemTempData> list = new ArrayList<>();

    private int BATCH_COUNT = 100;

    private int middleBatchLen = 20;

    private int COUNT_NUM = 0;

    private Long contractId;

    private StringBuilder errCountNum = new StringBuilder("");

    public PriContItemTempListener(PriContItemTempMapper priContItemTempMapper, CoreUser user, Long contractId) {
        this.priContItemTempMapper = priContItemTempMapper;
        this.user = user;
        this.contractId = contractId;
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        /*
        count 记录模板表头有几个，用以判断用户导入的表格是否和模板完全一致
        如果用户导入表格较模板的表头多，但其余符合模板，这样不影响则不需要
         */
        int count = 0;
        // 获取数据实体的字段列表
        Field[] fields = PriContItemTempData.class.getDeclaredFields();
        // 遍历字段进行判断
        for (Field field : fields) {
            // 获取当前字段上的ExcelProperty注解信息
            ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
            // 判断当前字段上是否存在ExcelProperty注解
            if (fieldAnnotation != null) {
                ++count;
                // 存在ExcelProperty注解则根据注解的index索引到表头中获取对应的表头名
                String headName = headMap.get(fieldAnnotation.index());
                // 判断表头是否为空或是否和当前字段设置的表头名不相同
                if (StringUtils.isNull(headName) || !headName.equals(fieldAnnotation.value()[0])) {
                    // 如果为空或不相同，则抛出异常不再往下执行
                    throw new RuntimeException("模板错误，请检查导入模板");
                }
            }
        }
        // 判断用户导入表格的标题头是否完全符合模板
        if (count != headMap.size()) {
            throw new RuntimeException("模板错误，请检查导入模板");
        }
    }

    @Override
    public void invoke(PriContItemTempData priContItemTempData, AnalysisContext analysisContext) {
        // 去掉头的行数
        Integer total = analysisContext.getTotalCount() - 1;
        if (total <= 0) {
            return;
        }
        // 初始化数据
        priContItemTempData.setCreatedBy(user.getId());
        priContItemTempData.setLastUpdatedBy(user.getId());
        priContItemTempData.setCorpid(user.getCorpid());
        priContItemTempData.setOrgId(user.getOrgId());
        priContItemTempData.setPostnId(user.getPostnId());
        priContItemTempData.setContractId(contractId);

        // 添加到集合
        list.add(priContItemTempData);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        try {
            this.saveData();
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("数据读取完成!");
    }

    /**
     * 保存
     * @throws Exception
     */
    private void saveData() throws Exception {
        if (null == list || list.size() == 0) {
            return;
        }
        // 计数器
        int count = 1;
        List<PriContItemTempData> toInsertPriContItemTempDataList = new ArrayList<>();
        List<Long> ids = new ArrayList<>();
        for (PriContItemTempData priContItemTempData : list) {
            toInsertPriContItemTempDataList.add(priContItemTempData);
            ids.add(priContItemTempData.getId());
            if (count == BATCH_COUNT) {
                try {
                    priContItemTempMapper.batchInserts(toInsertPriContItemTempDataList);
                } catch (Exception e) {
                    this.middleImport(toInsertPriContItemTempDataList);
                }
                count = 1;
                toInsertPriContItemTempDataList.clear();
                ids.clear();
            } else {
                count++;
            }
        }
        // 扫尾
        if (count > 0) {
            try {
                // 批量插入
                priContItemTempMapper.batchInserts(toInsertPriContItemTempDataList);
            } catch (Exception e) {
                try {
                    this.middleImport(toInsertPriContItemTempDataList);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            // 重新计数
            count = 1;
            // 清空list，重新塞数据
            toInsertPriContItemTempDataList.clear();
            ids.clear();
        }
    }



    private void middleImport(List<PriContItemTempData> priContItemTempDataList) throws Exception {
        // 计数器
        int count = 1;
        List<PriContItemTempData> toInsertPriContItemTempList = new ArrayList<>();
        List<Long> ids = new ArrayList<>();
        for (PriContItemTempData priContItemTempData : priContItemTempDataList) {
            toInsertPriContItemTempList.add(priContItemTempData);
            ids.add(priContItemTempData.getId());
            if (count == middleBatchLen) {
                try {
                    // 批量插入
                    priContItemTempMapper.batchInserts(toInsertPriContItemTempList);
                } catch (Exception e) {
                    this.singleInsert(toInsertPriContItemTempList);
                }
                count = 1;
                toInsertPriContItemTempList.clear();
                ids.clear();
            } else {
                count++;
            }
        }
        // 扫尾
        if (count > 0) {
            try {
                // 批量插入
                priContItemTempMapper.batchInserts(toInsertPriContItemTempList);
            } catch (Exception e) {
                this.singleInsert(toInsertPriContItemTempList);
            }
            // 重新计数
            count = 1;
            // 清空list，重新塞数据
            toInsertPriContItemTempList.clear();
            ids.clear();
        }
    }



    private void singleInsert(List<PriContItemTempData> partsCostTempList) {
        for (PriContItemTempData partsCostTempDataTemp : partsCostTempList) {
            try {
                partsCostTempDataTemp.setCheckStatus("New");
                priContItemTempMapper.addData(partsCostTempDataTemp);
            } catch (Exception e) {
                e.printStackTrace();
                String errorMsg = e.getMessage();
                if (!StringUtils.isNull(errorMsg) && errorMsg.length() > 1000) {
                    errorMsg = errorMsg.substring(0, 1000);
                }
                partsCostTempDataTemp.setErrorMsg(errorMsg);
                partsCostTempDataTemp.setCheckStatus("UPLOAD_FAIL");
                try {
                    priContItemTempMapper.addErrorData(partsCostTempDataTemp);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private boolean isLineNullValue(Object data) {
        if (data instanceof String) {
            return StringUtils.isNull((String)data);
        }
        try {
            List<Field> fields = Arrays.stream(data.getClass().getDeclaredFields())
                    .filter(f -> f.isAnnotationPresent(ExcelProperty.class))
                    .collect(Collectors.toList());
            List<Boolean> lineNullList = new ArrayList<>(fields.size());
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(data);
                if (StringUtils.isNull((String)value)) {
                    lineNullList.add(Boolean.TRUE);
                } else {
                    lineNullList.add(Boolean.FALSE);
                    return false;
                }
            }
            return lineNullList.stream().allMatch(Boolean.TRUE::equals);
        } catch (Exception e) {
            logger.error("读取数据行[{}]解析失败: {}", data, e.getMessage());
        }
        return true;
    }
}
